package com.fufu.thread;

/**
 * 死锁与可重入锁
 * @author: BlcakTiger
 * @date: 2023/2/11 21:49
 * @contact: hsf6661@163.com
 */
public class DeadLock {

    public static void main(String[] args) {
        Instance1 instance1 = new Instance1();
        new Thread(()->{
            instance1.add(1);
        }).start();
        new Thread(()->{
            instance1.dec(1);
        }).start();
    }
}

/**
 * 创建一个使用可重入锁的实例
 * synchronized修饰方法默认使用this实例作为锁的对象
 * 如下方法中，add方法中又调用了使用同一个锁的dec方法
 * 对同一个线程，能否在获取到锁以后继续获取同一个锁？
 * 答案是肯定的。JVM允许同一个线程重复获取同一个锁，这种能被同一个线程反复获取的锁，就叫做可重入锁。
 * Java的线程锁是可重入锁。所以，获取锁的时候，不但要判断是否是第一次获取，还要记录这是第几次获取。每获取一次锁，记录+1，每退出synchronized块，记录-1，减到0的时候，才会真正释放锁。
 */
class Instance{

    private int count = 0;

    public synchronized void add(int n){
        if (n < 0){
            dec(-n);
        }else{
            count += n;
        }
    }

    public synchronized void dec(int n){
        count += n;
    }
}

/**
 * 创建一个死锁的实例
 * 在这个实例中，add()方法与dec()分别先获取了不同的锁，并同时等待对方释放锁，但它们不获取到对方的锁也无法释放自己的锁，故而造成死锁问题
 */
class Instance1{

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    private int count = 0;

    public void add(int n){
        synchronized(lock1){
            count += n;
            synchronized (lock2){
                System.out.println(count);
            }
        }
    }

    public void dec(int n){
        synchronized(lock2){
            count -= n;
            synchronized(lock1){
                System.out.println(count);
            }
        }
    }

}
